Skip to content

UCT/IB/MLX5: Track RC send PSN with path MTU - #11821

Open
roiedanino wants to merge 21 commits into
openucx:masterfrom
roiedanino:pr11684-rc-psn
Open

UCT/IB/MLX5: Track RC send PSN with path MTU#11821
roiedanino wants to merge 21 commits into
openucx:masterfrom
roiedanino:pr11684-rc-psn

Conversation

@roiedanino

Copy link
Copy Markdown
Contributor

What?

Track the PSN that will be used by the next RC mlx5 send WQE.

Cache the path MTU programmed on the connected RC QP and use it to advance the tracked PSN for RC send operations.

Why?

Follow-up RC recovery logic needs a stable mapping from posted WQEs to their first packet sequence number. Using the interface MTU can miscount packets when the connected QP negotiated a different path MTU.

This change is split from #11684 and is intentionally limited to RC. DC, GGA, and recovery classification state are outside its scope.

How?

Cache path_mtu - 1 as a 16-bit mask and log2(path_mtu) as an 8-bit shift when the RC data QP is connected. Packet counts use (length + mask) >> shift, avoiding division and an out-of-line MTU lookup on the send path.

Advance next_first_psn after successful inline, data-pointer, IOV, tag, and SGL posts, wrapping in the 24-bit RC PSN space.

@roiedanino roiedanino self-assigned this Aug 24, 2026
@roiedanino
roiedanino marked this pull request as ready for review August 24, 2026 15:19
@roiedanino

Copy link
Copy Markdown
Contributor Author

@svc-nvidia-pr-review

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
@svc-ucx

svc-ucx commented Aug 24, 2026

Copy link
Copy Markdown

🤖 CI Triage AgentUCX PR (Tests BlueField on worker 0) · commit ab74f2b1

TL;DR: The BlueField gtest run aborted on ucs_assert(txwq->path_mtu_shift > 0) in gga_mlx5/uct_p2p_rma_test.get_zcopy, because the new PSN-tracking commit only initializes txwq->path_mtu_* in the RC endpoint connect path, while the GGA transport has its own connect_to_ep_v2 that never calls uct_rc_mlx5_txwq_set_path_mtu(). Fix: set the path MTU on the txwq in uct_gga_mlx5_ep_connect_to_ep_v2() (or push the call down into the shared devx_connect_qp helper).

Full analysis

Summary: gtest shard 1 aborted (core dumped) during gga_mlx5/uct_p2p_rma_test.get_zcopy/0 <gga_mlx5/mlx5_0:1> with assertion txwq->path_mtu_shift > 0 failed at rc_mlx5.inl:472, failing the "BlueField on worker 0" job (make: *** [Makefile:4713: test] Aborted (core dumped)).

Root cause: Commit ab74f2b1 ("UCT/IB/MLX5: Track RC send PSN with path MTU", the PR head) added per-txwq PSN accounting: uct_rc_mlx5_num_packets() (rc_mlx5.inl:468-477) now asserts txwq->path_mtu_shift > 0 and is invoked from uct_rc_mlx5_txwq_update_psn() inside uct_rc_mlx5_base_ep_zcopy_post() / put_sgl_zcopy (rc_mlx5_ep.c:293). The fields are initialized only by uct_rc_mlx5_txwq_set_path_mtu(), which the commit added at exactly one call site: uct_rc_mlx5_ep_connect_to_ep_v2() (src/uct/ib/mlx5/rc/rc_mlx5_ep.c:979). The GGA transport derives its EP from uct_rc_mlx5_base_ep_t and reuses uct_rc_mlx5_base_ep_zcopy_post() for both put_zcopy and get_zcopy, but connects through its own uct_gga_mlx5_ep_connect_to_ep_v2() (src/uct/ib/mlx5/gga/gga_mlx5.c:503-542), which calls uct_rc_mlx5_iface_common_devx_connect_qp() directly and never sets path_mtu_mask/path_mtu_shift. They stay zero from EP construction, so the first GGA zcopy send trips the assert on this assert-enabled (BlueField debug) build. Note path_mtu is already computed locally at gga_mlx5.c:516/521 — it is simply never propagated to the txwq.

Implicated commit: [REDACTED:Hex High Entropy String] — Roie Danino, "UCT/IB/MLX5: Track RC send PSN with path MTU"

File: src/uct/ib/mlx5/gga/gga_mlx5.c:528-533 (missing init); assert at src/uct/ib/mlx5/rc/rc_mlx5.inl:472; existing init at src/uct/ib/mlx5/rc/rc_mlx5_ep.c:979

Suggested fix: Preferred: move the initialization into the shared connect helper so every transport that owns an uct_ib_mlx5_txwq_t gets it — i.e. call uct_rc_mlx5_txwq_set_path_mtu(txwq, path_mtu) inside uct_rc_mlx5_ep_connect_qp()/uct_rc_mlx5_iface_common_devx_connect_qp() and drop the standalone call at rc_mlx5_ep.c:979. Minimal fix: in uct_gga_mlx5_ep_connect_to_ep_v2(), right after the successful uct_rc_mlx5_iface_common_devx_connect_qp() call (gga_mlx5.c:533), add:

uct_rc_mlx5_txwq_set_path_mtu(&ep->super.tx.wq, path_mtu);

Additionally consider giving path_mtu_shift a safe default (from iface->super.super.config.path_mtu) at txwq creation so any other/future non-RC user of uct_rc_mlx5_base_ep_zcopy_post() cannot hit this again, and audit for other uct_rc_mlx5_base_ep_* reusers (e.g. put_sgl_zcopy paths) that bypass the RC connect flow.

Related: PR #11821 (branch pr11684-rc-psn, follow-up to #11684); no existing issue found for this assertion.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id 5bc245f5-4b4b-405a-9a2a-8b34182e0541 in the triage console for the audit trail.

Report the payload length while building mlx5 data segments so RC PSN tracking does not walk the zcopy IOV again on the send fast path.
Place the cached path MTU fields after the send indices so they do not introduce padding before the MMIO register pointer.
Keep the next-PSN counter free-running so RC posting only performs an addition. Mask the value when exposing a hardware PSN through the accessor and VFS.
@svc-ucx

svc-ucx commented Aug 24, 2026

Copy link
Copy Markdown

🤖 CI Triage AgentUCX PR (AddressSanitizer roce on worker 0) · commit 119b4a4d

TL;DR: The ASAN gtest aborted on ucs_assert(txwq->path_mtu_shift > 0) in rc_mlx5.inl:472 during gga_mlx5/uct_p2p_rma_test.get_zcopy/0, because the new PSN-tracking code (PR #11821, commit ab74f2b) initializes txwq->path_mtu_shift only in the RC ep connect path and not in the GGA ep connect path — add the uct_rc_mlx5_txwq_set_path_mtu() call to uct_gga_mlx5_ep_connect_to_ep_v2().

Full analysis

Summary: roce on worker 0 (AddressSanitizer) gtest crashed with a fatal assertion + core dump: rc_mlx5.inl:472 Assertion 'txwq->path_mtu_shift > 0' failed in gga_mlx5/uct_p2p_rma_test.get_zcopy/0 <gga_mlx5/mlx5_0:1>, causing make: *** [Makefile:4713: test] Aborted (core dumped).

Root cause: PR #11821 adds RC send-PSN tracking based on path MTU: uct_rc_mlx5_base_ep_zcopy_post() now calls uct_rc_mlx5_txwq_update_psn()uct_rc_mlx5_num_packets(), which asserts txwq->path_mtu_shift > 0 (src/uct/ib/mlx5/rc/rc_mlx5.inl:468-477). The field is populated by uct_rc_mlx5_txwq_set_path_mtu(), which the commit added to the RC connect path (src/uct/ib/mlx5/rc/rc_mlx5_ep.c:979, right after uct_rc_mlx5_ep_connect_qp). The GGA transport is a separate ep class (uct_gga_mlx5_ep_t) with its own connect routine, uct_gga_mlx5_ep_connect_to_ep_v2() (src/uct/ib/mlx5/gga/gga_mlx5.c:502-542): it resolves path_mtu and passes it to uct_rc_mlx5_iface_common_devx_connect_qp() but never calls uct_rc_mlx5_txwq_set_path_mtu(). So path_mtu_shift/path_mtu_mask stay zero, and the first GGA MMO get/put zcopy post trips the assert (visible only in assert-enabled builds such as this ASAN job — hence the RC/DC tests in the same run passed).

Implicated commit: ab74f2b — "UCT/IB/MLX5: Track RC send PSN with path MTU", Roie Danino (branch pr11684-rc-psn, PR #11821)

File: src/uct/ib/mlx5/gga/gga_mlx5.c:528-534 (missing init); assertion site src/uct/ib/mlx5/rc/rc_mlx5.inl:472

Suggested fix: In uct_gga_mlx5_ep_connect_to_ep_v2(), after uct_rc_mlx5_iface_common_devx_connect_qp() returns UCS_OK, add:

uct_rc_mlx5_txwq_set_path_mtu(&ep->super.tx.wq, path_mtu);

mirroring rc_mlx5_ep.c:979. Better still, move the call inside the shared QP-connect helpers (uct_rc_mlx5_ep_connect_qp / uct_rc_mlx5_iface_common_devx_connect_qp) so every txwq that gets a path_mtu is initialized exactly once, and audit the remaining txwq owners that go through a non-RC connect path (DC DCIs / dci_pool init, TM QP) for the same omission. Optionally make uct_rc_mlx5_num_packets() defensive with a clearer fatal message naming the uninitialized txwq.

Related: #11821 (the PR under test; base work PR #11684)

@svc-ucx

svc-ucx commented Aug 25, 2026

Copy link
Copy Markdown

🤖 CI Triage AgentUCX PR (ucx_perftest over MAD RTE Setup Server) · commit 4043a278

TL;DR: The build broke — src/uct/ib/mlx5/rc/rc_mlx5.inl:489 references MLX5_OPCODE_MMO unconditionally, but this CI agent's rdma-core doesn't declare it (configure: checking whether MLX5_OPCODE_MMO is declared... no), so every compilation unit including rc_mlx5.inl fails with -Werror. Guard the MMO check with HAVE_MLX5_MMO (or add a UCT_IB_MLX5_OPCODE_MMO fallback macro).

Full analysis

Summary: "Setup Server" stage failed at make -s -j48 while building src/uct/ib/mlx5: error: 'MLX5_OPCODE_MMO' undeclared (first use in this function) in uct_rc_mlx5_txwq_update_psn, breaking rc_mlx5_ep.lo, rc_mlx5_iface.lo, rc_mlx5_common.lo, rc_mlx5_devx.lo, dc_mlx5.lo, dc_mlx5_ep.lo.

Root cause: MLX5_OPCODE_MMO comes from a newer infiniband/mlx5dv.h. UCX treats it as optional: src/uct/ib/configure.m4:134-137 only defines HAVE_MLX5_MMO/has_mlx5_mmo if the symbol is declared, and MMO-dependent code (GGA transport, src/uct/ib/mlx5/gga/gga_mlx5.c) is compiled only under AM_CONDITIONAL([HAVE_MLX5_MMO]) (configure.m4:322). The build log for this agent shows checking whether MLX5_OPCODE_MMO is declared... no and IB modules: < mlx5 > with GGA absent. The new PSN-tracking code added the raw MLX5_OPCODE_MMO reference into rc_mlx5.inl, a header included by all RC/DC mlx5 sources, which are built unconditionally — so on an older rdma-core the identifier is undefined and -Werror turns it into a hard failure. This is purely a compile-time portability regression, not a runtime/test issue.

Implicated commit: [REDACTED:Hex High Entropy String] — "UCT/IB/MLX5: Limit PSN tracking to RC packet WQEs", Roie Danino (part of PR #11821 / branch pr11684-rc-psn; builds on ab74f2b, 31d155a, 119b4a4 by the same author)

File: src/uct/ib/mlx5/rc/rc_mlx5.inl:489

Suggested fix: Don't reference MLX5_OPCODE_MMO from an unconditionally compiled header. Either:

  1. Add a portable alias in src/uct/ib/mlx5/ib_mlx5.h (next to the existing HAVE_DECL_MLX5DV_UAR_ALLOC_TYPE_* fallbacks around lines 81-96):
#if HAVE_MLX5_MMO
#  define UCT_IB_MLX5_OPCODE_MMO MLX5_OPCODE_MMO
#else
/* MMO opcode is unavailable in this rdma-core; value is never posted */
#  define UCT_IB_MLX5_OPCODE_MMO 0x2fu
#endif

and use UCT_IB_MLX5_OPCODE_MMO at rc_mlx5.inl:489; or

  1. Cleaner: drop the opcode comparison entirely and rely on the already-defined UCT_RC_MLX5_OPCODE_FLAG_NO_PSN (rc_mlx5_common.h:45) — have the GGA/MMO send paths pass that flag, so uct_rc_mlx5_txwq_update_psn() needs no MMO-specific knowledge.

Also worth adding a CI/build check on a host without MLX5_OPCODE_MMO (i.e. GGA disabled) to catch this class of regression, since the MMO-guarded GGA transport is not built on all agents.

Related: PR #11821 (this PR), predecessor PR #11684 (branch name pr11684-rc-psn); no existing issue found for MLX5_OPCODE_MMO undeclared.

🛡️ This comment had 1 potential secret(s) redacted (Hex High Entropy String). See request_id c6258d3c-d1cf-493b-bffd-4b3a50d3b846 in the triage console for the audit trail.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment on lines +455 to +456
static UCS_F_ALWAYS_INLINE void
uct_rc_mlx5_txwq_set_path_mtu(uct_ib_mlx5_txwq_t *txwq,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect this function to be called from control path, maybe move it to .h/.c?

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl
Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment on lines +995 to +997
wqe_size = sizeof(*ctrl) + sizeof(*dma_seg) + (2 * sizeof(*dptr));
opmod = UCT_IB_MLX5_OPMOD_MMO_DMA;
message_length = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

align pls

Comment thread src/uct/ib/mlx5/ib_mlx5.c Outdated
Comment on lines 703 to 704
txwq->hw_ci = 0xFFFF;
txwq->flags = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls align too

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment on lines +475 to +476
(message_length + txwq->path_mtu_mask) >>
txwq->path_mtu_shift);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a variable for this math and ucs_assert(res > 0), I think ucs_max is redundant here sinse NOP is handled separately

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment on lines +464 to +465
txwq->path_mtu_mask = mtu - 1;
txwq->path_mtu_shift = ucs_ilog2(mtu);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe cache only path_mtu_shift and calc UCS_MASK(path_mtu_shift) inplace?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thought about it, that will add about 2-3 operations in the fast path:

  1. res = 1 << mtu_shift
  2. mask = (res - 1)

and only then the division itself

wdyt?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that is better - the couple of instructions on register or double load from the same cache line, it may be arch specific but if we can save some space for +/- the same price - why not... I would check with asm + test MSG rate bench

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment on lines +916 to +921
dptr = (struct mlx5_wqe_data_seg *)((char *)inl + inl_seg_size);
wqe_size = ctrl_av_size + inl_seg_size +
uct_ib_mlx5_set_data_seg_iov(txwq, dptr, iov, iovcnt);
opmod = 0;
wqe_size = ctrl_av_size + inl_seg_size +
uct_ib_mlx5_set_data_seg_iov_length(
txwq, dptr, iov, iovcnt, &iov_length);
opmod = 0;
message_length = iov_length + sizeof(*rch) + am_hdr_len;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

align pls

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
Comment on lines +934 to +939
dptr = uct_ib_mlx5_txwq_wrap_exact(txwq, (char *)inl + inl_seg_size);
wqe_size = ctrl_av_size + inl_seg_size +
uct_ib_mlx5_set_data_seg_iov(txwq, dptr, iov, iovcnt);
opmod = 0;
wqe_size = ctrl_av_size + inl_seg_size +
uct_ib_mlx5_set_data_seg_iov_length(
txwq, dptr, iov, iovcnt, &iov_length);
opmod = 0;
message_length = iov_length + sizeof(struct ibv_tmh);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alignment

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/ib_mlx5.h Outdated
uct_ib_mlx5_qp_t super;
uint16_t sw_pi; /* PI for next WQE */
uint16_t prev_sw_pi; /* PI where last WQE *started* */
uint32_t next_first_psn; /* Free-running PSN counter */

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new next_first_psn / path_mtu_mask / path_mtu_shift state and the uct_ib_mlx5_txwq_get_next_first_psn() accessor are only read by the gtest and the new VFS file; there is no production consumer in this PR. This is fine as preparatory infrastructure, but worth confirming a follow-up will consume it so the state does not remain dead (REVIEW.md "avoid redundant state").

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be used in followup PRs

@svc-ucx

svc-ucx commented Aug 25, 2026

Copy link
Copy Markdown

🤖 CI Triage AgentUCX PR (AddressSanitizer gpu on worker 1) · commit 9c3c513a

TL;DR: The ASAN gtest run aborted on a fatal debug assertion in uct_rc_mlx5_common_post_send() (rc_mlx5.inl:514) during dcx/test_ucp_fault_tolerance.initiator_failure/6 <dc_x/AM|FLUSH> — UCP's fault-tolerance lane recovery posted a regular AM-zcopy WQE on a DC DCI whose txwq is still flagged UCT_IB_MLX5_TXWQ_FLAG_FAILED (only NOP/flush WQEs are allowed in that state), because the DCI is reset only if it was released back to the pool.

Full analysis

Summary: make test in the "AddressSanitizer gpu on worker 1" job aborted (core dumped) at 16:56:39 with rc_mlx5.inl:514 Assertion '!(txwq->flags & UCT_IB_MLX5_TXWQ_FLAG_FAILED)' failed, backtrace ucp_am_send_nbx → uct_dc_mlx5_ep_am_zcopy → ucs_fatal_error_format, right after "Checking recovery status..." in dcx/test_ucp_fault_tolerance.initiator_failure/6 <dc_x/AM|FLUSH>.

Root cause: On a DCI completion error, uct_dc_mlx5_iface_handle_failure() marks the DCI's send WQ as failed (uct_ib_mlx5_txwq_update_flags(..., UCT_IB_MLX5_TXWQ_FLAG_FAILED, 0), dc_mlx5.c:1439). The flag is only cleared by uct_dc_mlx5_iface_reset_dci() (dc_mlx5.c:1907-1917), and uct_dc_mlx5_ep_handle_failure() calls that reset only if the DCI was successfully returned to the pool (if (ep->dci == UCT_DC_MLX5_EP_NO_DCI), dc_mlx5_ep.c:1787-1808). In the UCP fault-tolerance flow the UCT ep is not destroyed — after the injected lane failure UCP recovers the lane and re-sends on the same DC ep/DCI. If the DCI was still held by the ep (outstanding/pending work at error time), it is never reset, so the next non-NOP send hits the "if FAILED, allow only NOP sends (endpoint flush)" contract check and ucs_assert fatals. This is an error-handling/recovery ordering bug in the DC transport vs. UCP FT lane rebuild, not a consequence of the PSN work in this PR: the new PSN code (uct_rc_mlx5_txwq_add_psn/update_psn, rc_mlx5.inl:479-498) is a no-op for UCT_IB_QPT_DCI, and the failing assert is pre-existing debug instrumentation (UCS_ENABLE_ASSERT-only, hence only visible in this debug/ASAN build).

Implicated commit: Not the PR head (9c3c513 "UCT/IB/MLX5: Centralize RC PSN update guard", Roie Danino — PSN path is RC-only). The exposed defect belongs to the UCP FT lane-recovery series that reuses failed lanes: db208ee (#11563) / 9db2e48 (#11562) / 4cb9dbb (#11266), Evgeny Leksikov, combined with DC failure handling in dc_mlx5_ep.c.

File: src/uct/ib/mlx5/rc/rc_mlx5.inl:511-515 (assert site); real defect at src/uct/ib/mlx5/dc/dc_mlx5_ep.c:1787-1808 and src/uct/ib/mlx5/dc/dc_mlx5.c:1439,1883-1918

Suggested fix: Make the DC transport guarantee that no non-NOP WQE can be posted on a failed DCI: in uct_dc_mlx5_ep_handle_failure(), force the DCI out of the ep (detach) and call uct_dc_mlx5_iface_reset_dci() unconditionally once outstanding work has been purged, or have the DC ep send fast-path return UCS_ERR_CONNECTION_RESET/UCS_ERR_NO_RESOURCE while txwq->flags & UCT_IB_MLX5_TXWQ_FLAG_FAILED is set (so UCP FT retries after the reset), instead of relying on a debug-only assert. This is the same class of change as the in-progress error-handler work in PR #11823; until that lands, this dc_x AM|FLUSH FT variant will intermittently kill the ASAN/debug gtest job, so re-running PR #11821 is safe but the FT/DC issue should be tracked separately (optionally skip dcx/test_ucp_fault_tolerance.initiator_failure under UCS_ENABLE_ASSERT to unblock CI).

Related: #11823 (UCT/IB/MLX5: rc support in progress error handler), #11563, #11397 (previous disabling of a failing fault-tolerance test), PR under test: #11821

Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl
uct_ib_mlx5_txwq_t *txwq,
uct_ib_mlx5_qp_attr_t *attr);

void uct_rc_mlx5_txwq_set_path_mtu(uct_ib_mlx5_txwq_t *txwq,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor — misaligned continuation line. The enum ibv_mtu path_mtu line has one extra leading space; suggested:

Suggested change
void uct_rc_mlx5_txwq_set_path_mtu(uct_ib_mlx5_txwq_t *txwq,
void uct_rc_mlx5_txwq_set_path_mtu(uct_ib_mlx5_txwq_t *txwq,
enum ibv_mtu path_mtu);

The same misalignment exists in the definition in rc_mlx5_ep.c.

valid_length, buffer, max);
}

void uct_rc_mlx5_txwq_set_path_mtu(uct_ib_mlx5_txwq_t *txwq,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor — misaligned continuation line. The enum ibv_mtu path_mtu line has one extra leading space, matching the misalignment in the declaration in rc_mlx5.h.

Comment thread src/uct/ib/mlx5/ib_mlx5.c Outdated
uct_ib_mlx5_set_ctrl_qpn_ds(uct_ib_mlx5_txwq_get_wqe(txwq, 0xffff), 0, 1);
}


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor — double blank lines. The new uct_ib_mlx5_txwq_vfs_show_next_first_psn has two blank lines before and after it, while the surrounding functions in this file are separated by a single blank line. Please use a single blank line for consistency.

Comment thread src/uct/ib/mlx5/ib_mlx5.c Outdated
strb, "%u\n", uct_ib_mlx5_txwq_get_next_first_psn(txwq));
}


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor — double blank lines after uct_ib_mlx5_txwq_vfs_show_next_first_psn. Please use a single blank line for consistency.

@svc-nvidia-pr-review

Copy link
Copy Markdown

Observation (non-blocking): uct_rc_mlx5_txwq_update_psn guards on qp_type == IBV_QPT_RC and then calls uct_rc_mlx5_txwq_add_psn, which repeats the same guard. The double guard is harmless (both compile-time constants, optimized away) but redundant; a single check would be cleaner.

Observation (non-blocking): DC (UCT_IB_QPT_DCI) paths never call num_packets because the PSN helpers early-return for non-RC, so the path_mtu_shift > 0 assert there is not a concern. GGA uses MLX5_OPCODE_MMO, which returns before update_psn, so GGA correctly skips PSN accounting even though it sets path_mtu_shift at connect.

Observation (non-blocking): The next_first_psn counter currently has no consumer other than VFS and the new gtest; this looks like intentional infrastructure for a follow-up. Worth confirming that matches the PR intent.

Test coverage: The new test_rc_mlx5_psn tests cover the path-MTU-based PSN increment and the 24-bit wrap. There is no test exercising a zero-length RC bcopy/put_sgl_zcopy, which is exactly the case that trips finding #1 — adding one would guard against the assert regression.

Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
Signed-off-by: Roie Danino <rdanino@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl Outdated
{
ucs_assert(txwq->path_mtu_shift > 0);

return ucs_max(1u, (message_length + txwq->path_mtu_mask) >>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need ucx_max here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zero-length PUT_ZCOPY is valid (UCT_CHECK_LENGTH(..., 0, ...)) and still posts an RC WQE that consumes one PSN. Without ucs_max, the tracked PSN would not advance; NOP is handled separately.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so maybe handle 0-lenght PUT_ZCOPY separately as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zero length is not specific to PUT_ZCOPY. PUT_BCOPY and individual PUT_SGL_ZCOPY entries can also post zero-length RDMA WRITE WQEs, each consuming one PSN, while PUT_SHORT already counts one. Keeping ucs_max(1u, ...) in the common helper handles all posted RC WQEs consistently. NOP and MMO bypass this helper because they do not consume an RC wire PSN.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl
Comment thread src/uct/ib/mlx5/rc/rc_mlx5_ep.c
Comment thread src/uct/ib/mlx5/ib_mlx5.h Outdated
uct_ib_mlx5_qp_t super;
uint16_t sw_pi; /* PI for next WQE */
uint16_t prev_sw_pi; /* PI where last WQE *started* */
uint32_t next_first_psn; /* Free-running PSN counter */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32_t next_first_psn; /* Free-running PSN counter */
uint32_t next_wqe_psn; /* 1st PSN of the next WQE to be posted */

Signed-off-by: Roie Danino <rdanino@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@@ -212,6 +212,7 @@ uct_rc_mlx5_base_ep_put_sgl_zcopy(uct_ep_h tl_ep, void * const *buffers,
uct_ib_mlx5_txwq_t *txwq = &ep->tx.wq;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DM short paths (put_short/am_short/am_short_iov via uct_rc_mlx5_common_ep_short_dm, and tag_eager_short) post an RC WQE but do not call uct_rc_mlx5_txwq_add_psn, so next_wqe_psn drifts when device memory is used (HAVE_IBV_DM and payload fits in DM segment). Unlike their inline counterparts (uct_rc_mlx5_txqp_inline_post, uct_rc_mlx5_txqp_inline_iov_post), the PSN is not advanced. This is non-blocking since the counter currently has no functional consumer beyond VFS/gtest, but if the intent is accurate PSN tracking, the DM path should also bump the PSN or be explicitly documented as excluded.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DM path is already covered indirectly through uct_rc_mlx5_common_txqp_bcopy_post() -> uct_rc_mlx5_txqp_dptr_post(), which updates PSN using hdr_len + iov_length. RC passes IBV_QPT_RC, while the DC update is compiled out, so an additional bump would double-count.

@@ -144,6 +144,90 @@ UCS_TEST_P(test_rc, fence_am_short_consumed, "RC_FENCE=weak")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Residual coverage gap: the new test_rc_mlx5_psn only exercises inline am_short and put_zcopy; it does not cover the DM short path or the put_sgl_zcopy multi-WQE PSN accumulation, so the DM PSN drift would not be caught by CI.

Comment thread src/uct/ib/mlx5/ib_mlx5.inl Outdated
Comment on lines +544 to +550
static UCS_F_ALWAYS_INLINE
size_t uct_ib_mlx5_set_data_seg_iov(uct_ib_mlx5_txwq_t *txwq,
struct mlx5_wqe_data_seg *dptr,
const uct_iov_t *iov, size_t iovcnt)
{
return uct_ib_mlx5_set_data_seg_iov_length(txwq, dptr, iov, iovcnt, NULL);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: it looks redundant

Signed-off-by: Roie Danino <rdanino@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

uct_rc_mlx5_txwq_update_psn and uct_rc_mlx5_txwq_add_psn both guard on qp_type == IBV_QPT_RC; the double guard is redundant (both compile-time constants).

next_wqe_psn is stored unmasked while the accessor masks to 24 bits; the VFS file shows the masked value. Minor consistency point, not a bug.

The new tests run only under HAVE_MLX5_DV with a device that supports PUT_ZCOPY and mismatched path MTUs between the two entities, which limits coverage.

Comment thread src/uct/ib/mlx5/ib_mlx5.h
} uct_ib_mlx5_txwq_t;


static UCS_F_ALWAYS_INLINE uint32_t

@jeynmann jeynmann Aug 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: extract a small helper to centralize the 24-bit PSN masking, so future changes related to PSN would reuse this and make it easier to maintain.

Something like:

static UCS_F_ALWAYS_INLINE uint32_t
uct_ib_mlx5_psn24(uint32_t psn)
{
    return psn & UCS_MASK(24);
}

We might need this in later PRs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to keep it inline for now and introduce a shared helper in the follow-up PR when it has multiple users.

Comment thread src/uct/ib/mlx5/ib_mlx5.inl Outdated
size_t uct_ib_mlx5_set_data_seg_iov(uct_ib_mlx5_txwq_t *txwq,
struct mlx5_wqe_data_seg *dptr,
const uct_iov_t *iov, size_t iovcnt)
size_t uct_ib_mlx5_set_data_seg_iov_length(uct_ib_mlx5_txwq_t *txwq,

@jeynmann jeynmann Aug 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe update the existing uct_ib_mlx5_set_data_seg_iov signature and its callers instead of introducing a new uct_ib_mlx5_set_data_seg_iov_length function, since length is confusing and looks like an input.

Think about adding iov_length to the last argument and updating the 4 call sites in this PR to use the new parameter name.

WDYT?

Signed-off-by: Roie Danino <rdanino@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

Signed-off-by: Roie Danino <rdanino@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Review complete — no issues found.

Signed-off-by: Roie Danino <rdanino@nvidia.com>
@svc-nvidia-pr-review

Copy link
Copy Markdown

🤖 Starting review — findings will be posted here when done.

#endif

uct_rc_mlx5_txwq_update_psn(txwq, qp_type, message_length);
if (opcode_flags == MLX5_OPCODE_RDMA_WRITE) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Zero-length RDMA_READ with message_length==0 would get update_psn(0)=0 PSN added because the special case only checks RDMA_WRITE, not RDMA_READ. This doesn't affect real paths (get_zcopy has a min length check and zero-length reads via dptr_post_iov don't occur), but it is a slight inconsistency with the dptr_post (bcopy) path which adds 1 for both READ and WRITE on the zero-length case.

Comment thread src/uct/ib/mlx5/rc/rc_mlx5.inl
Comment thread src/uct/ib/mlx5/ib_mlx5.h
@@ -686,13 +686,17 @@ typedef struct uct_ib_mlx5_txwq {
uct_ib_mlx5_qp_t super;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking (previously noted): next_wqe_psn is stored unmasked as uint32_t while the accessor masks to 24 bits.

@@ -144,6 +144,108 @@ UCS_TEST_P(test_rc, fence_am_short_consumed, "RC_FENCE=weak")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Residual coverage gap (already noted in prior rounds): the new test_rc_mlx5_psn tests require HAVE_MLX5_DV, PUT_ZCOPY support, and mismatched path MTUs between the two entities, so they will be skipped on many CI configurations.

@svc-nvidia-pr-review

Copy link
Copy Markdown

Non-blocking (previously noted): next_wqe_psn currently has no consumer beyond VFS/gtest, which appears to be intentional follow-up infrastructure.

@roiedanino
roiedanino enabled auto-merge (squash) August 27, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants